home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Presentations / Presentations ’90 / A⁄Rose Techniques / Interrupt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-11  |  5.8 KB  |  209 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    Interrupt.c - This file demonstrates ways to deal with hardware interrupts.
  3.  *
  4.  *    Mark D. Rustad.    6/11/90.
  5.  *
  6.  *    Note that this won't compile and certainly won't run.  Just make note of
  7.  *    the techniques demonstrated.
  8.  */
  9.  
  10. #include <clister.h>
  11. #include <os.h>
  12. #include <arose.h>
  13.  
  14. _TITLE("Interrupt.c - This file demonstrates ways to deal with hardware interrupts.")
  15. _SPACE("4,20,Definitions")
  16. /*
  17.  *    Definitions.
  18.  */
  19.  
  20. /*    The following saves A5 in the indicated location on the card.    */
  21.  
  22. pascal void    SaveA5_780(void) = {0x21CD, 0x0780};    // Save A5 in 0x0780
  23.  
  24. /*
  25.  *    Why I can get away with the above:  A/ROSE puts it's stuff starting at 0x400.
  26.  *    A/ROSE exception handling dumps the processor state into 0x600 and A/ROSE
  27.  *    code normally begins at 0x800.  This means that all the interrupt vector
  28.  *    space below 0x400 is available for use as well as space between the A/ROSE
  29.  *    exception area and 0x800.  It is reasonable for a designer designing code
  30.  *    that will control hardware on a card to make use of these areas (certainly
  31.  *    the interrupt vectors should be available.
  32.  *
  33.  *    It would be a very bad idea for a piece of fairly general purpose,
  34.  *    dynamically downloadable A/ROSE code to make any use of any of these areas,
  35.  *    since they may be in use by whatever is controlling the hardware on the
  36.  *    card it may be downloaded onto.
  37.  *
  38.  *    Since this example is dealing with interrupts, it must be controlling some
  39.  *    hardware.
  40.  */
  41.  
  42. pascal void Illegal() = 0x4AFC;        // Now we die!
  43.  
  44. typedef void (*funcPtr)();
  45.  
  46. _SPACE("4,20,Globals")
  47. /*
  48.  *    Globals.
  49.  */
  50.  
  51. AROSEmessage    *IntMsg;    // Points to message to be sent from interrupt rtn.
  52.  
  53. _SPACE("4,20,main")
  54. /*
  55.  *    main - No main, no gain...
  56.  */
  57.  
  58. void    main(void)
  59. {
  60.     register AROSEmessage    *mp;
  61.     void    IntRtn(AROSEmessage *);
  62.     extern void    Interrupt(void);
  63.  
  64.     /*
  65.      *    Initialize message for interrupt usage.
  66.      */
  67.  
  68.     if ((mp = GetMsg()) == 0)
  69.     {
  70.         /*    Most people just give up when there's a shortage
  71.          *    of message buffers at initialization.  Why should
  72.          *    this example be any different?
  73.          */
  74.         Illegal();
  75.     }
  76.  
  77.     mp->mTo = mp->mFrom;    // Since mFrom has our TID already
  78.     mp->mPriority = 100;    // Process interrupt messages first!
  79.     mp->mCode = 0x1001;        // My mCode for interrupt messages
  80.     mp->mSData[0] = (long) IntRtn;    // Pointer to routine
  81.     IntMsg = mp;            // Place in global
  82.  
  83.     SaveA5_780();            // Save our A5 value in 0x780 for interrupt routine
  84.  
  85.     /*
  86.      *    Now make hardware interrupt vector point at assembly routine.
  87.      */
  88.  
  89.     *(long*)0x6C = (long) Interrupt;
  90.  
  91.     /*
  92.      *    Lots of other stuff to do, for "real" things...
  93.      */
  94.  
  95.     DoOtherStuff();
  96.  
  97.     /*
  98.      *    Main loop.
  99.      */
  100.  
  101.     for (;;)
  102.     {
  103.         mp = Receive(0, 0, 0, 0);
  104.  
  105.         /*    This checks for completions from the next server.  This approach
  106.          *    assumes that the next server does not make requests to us, but
  107.          *    only replies.  Checks could be made on mCode.
  108.          */
  109.  
  110.         if (mp->mCode == 0x1001)
  111.         {
  112.             ((funcPtr)mp->mSData[0])(mp);    // Call routine to complete request
  113.             continue;        // Back up to the top of the for loop
  114.         }
  115.  
  116.         /*
  117.          *    This is probably followed by a normal mCode decode for requests.
  118.          *    Omitted here for brevity.  See MiddleMan.c for one example.
  119.          */
  120.     }
  121. }
  122.  
  123. _SPACE("4,20,IntRtn")
  124. /*
  125.  *    IntRtn - This routine gets called as a result of the interrupt routine
  126.  *            sending a message.
  127.  *
  128.  *    Inputs:
  129.  *        mp        - Points to the actual message buffer.
  130.  */
  131.  
  132. void    IntRtn(AROSEmessage *mp)
  133. {
  134.     /*
  135.      *    Process the data that the interrupt routine was trying to tell us
  136.      *    about.  This probably involves accessing some shared structures, etc.
  137.      *    specific to your application.  Often the shared structures may take
  138.      *    the form of some sort of circular buffer or list.
  139.      */
  140.  
  141.     IntMsg = mp;        // Enable subsequent notification
  142.  
  143.     if (WorkToDo)
  144.         DoTheWork();
  145. }
  146.  
  147. /*
  148.  *    Now let's play make believe (yes, my 3 year old is rubbing off on me).
  149.  *    Let's pretend that MPW C can switch to assembly just to keep everything for
  150.  *    this example in one file.  This is pure fantasy, folks...
  151.  */
  152.  
  153. #pragma asm on
  154.  
  155. Interrupt    Proc    Export
  156.         Import    IntMsg:Data
  157.         Import    PostRTE:Code            // A/ROSE exit
  158.  
  159.         MoveM.L    A0/A1/A5/D0-D2, -(A7)    // Save registers (assume we may call C code)
  160.         MoveA.L    $780, A5                // Set A5
  161.  
  162. SROffset    Equ    5*4                        // Size of registers on stack
  163.  
  164. *    Probably mess with the hardware here.
  165.  
  166.         ...
  167.         ...
  168.  
  169. *    Notify mainline of work to do.
  170.  
  171.         MoveA.L    IntMsg, A0
  172.         MoveQ    #0, D0
  173.         Move.L    D0, IntMsg                // Indicate message in use
  174.  
  175. *    We can get really fancy if we need to, by enabling interrupts while
  176. *    the Send takes place.  This isn't always needed, but has been known to
  177. *    be useful in high-speed non-DMA synchronous environments.  It is shown here
  178. *    as an interesting example.
  179.  
  180.         Move.L    A0, D0                    // See if we got the buffer
  181.         BEq.S    @leave                    // If no, get out
  182.  
  183.         Move.W    SROffset(A7), D0        // Get previous SR off stack
  184.         OrI.W    #$2000, D0                // Be sure supervisor bit remains set!
  185.         Move    D0, SR                    // Lower to previous IPL
  186.  
  187. *    Note that lowering the IPL will not cause a pile-up of messages to arrive
  188. *    at the main task because only one message is available.  This approach assumes
  189. *    that there are other data structures that the mainline looks at to locate
  190. *    work to do.  Notifications of some events may not work well this way.  In
  191. *    those cases, it is reasonable to keep a short list of pre-allocated message
  192. *    buffers and use those - perhaps even falling back on calling GetMsg if the
  193. *    list should ever be exhausted (GetMsg can be called from an interrupt routine,
  194. *    but it takes more time than one would like).
  195.  
  196. *    Continue with message send.
  197.  
  198.         Move.L    D1, mMessage.mOData(A0)    // Maybe put some info in the message
  199.         Send    A0                        // Send the message
  200. ;        Trap    #trSend        // This instead of "Send" will save 4 cycles
  201.  
  202. *    Hopefully the Send macro will get fixed to only generate the Trap instruction
  203. *    when the argument is simply A0.
  204.  
  205. @leave    MoveM.L    (A7)+, A0/A1/A5/D0-D2    // Restore registers
  206.         Jmp        PostRTE                    // Go through standard A/ROSE exit code
  207.  
  208.         EndP
  209.